home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 22 / Amiga Format AFCD22 (Jan 1998, Issue 106).iso / -in_the_mag- / converters / graphics / netpbm / source1 / pbm / pktopbm.c < prev    next >
C/C++ Source or Header  |  1997-11-16  |  10KB  |  339 lines

  1. /*
  2.   pktopbm, adapted from "pktopx in C by Tomas Rokicki" by AJCD 1/8/90
  3.   
  4.   compile with: cc -lpbm -o pktopbm pktopbm.c
  5.   */
  6.  
  7. #include <stdio.h>
  8. #include "pbm.h"
  9.  
  10. #define NAMELENGTH 80
  11. #define MAXROWWIDTH 3200
  12. #define MAXPKCHAR 256
  13.  
  14. typedef int integer ;
  15. typedef unsigned char quarterword ;
  16. typedef char boolean ;
  17. typedef quarterword eightbits ;
  18.  
  19. static FILE *pkfile ;
  20. static char pkname[NAMELENGTH+1] ;
  21. static integer pktopbm_pkloc = 0;
  22. static char *filename[MAXPKCHAR] ;
  23. static bit **bitmap = NULL ;
  24. static integer dynf ;
  25. static eightbits inputbyte ;
  26. static eightbits bitweight ;
  27. static integer repeatcount ;
  28. static integer flagbyte ;
  29.  
  30. /* add a suffix to a filename in an allocated space */
  31. static void
  32. pktopbm_add_suffix(name, suffix)
  33.      char *name, *suffix ;
  34. {
  35.    char *slash = rindex(name, '/');
  36.    char *dot = rindex(name, '.');
  37.  
  38.    if ((dot && slash ? dot < slash : !dot) && strcmp(name, "-"))
  39.       strcat(name, suffix);
  40. }
  41.  
  42. /* get a byte from the PK file */
  43. static eightbits pktopbm_pkbyte()
  44. {
  45.    pktopbm_pkloc++ ;
  46.    return(getc(pkfile)) ;
  47. }
  48.  
  49. /* get a 16-bit half word from the PK file */
  50. static integer get16()
  51. {
  52.    integer a = pktopbm_pkbyte() ;
  53.    return((a<<8) + pktopbm_pkbyte()) ;
  54. }
  55.  
  56. /* get a 32-bit word from the PK file */
  57. static integer get32()
  58. {
  59.    integer a = get16() ;
  60.    if (a > 32767) a -= 65536 ;
  61.    return((a<<16) + get16()) ;
  62. }
  63.  
  64. /* get a nibble from current input byte, or new byte if no current byte */
  65. static integer getnyb()
  66. {
  67.    eightbits temp ;
  68.    if (bitweight == 0) {
  69.       inputbyte = pktopbm_pkbyte() ;
  70.       bitweight = 16 ;
  71.    }
  72.    temp = inputbyte / bitweight ;
  73.    inputbyte -= temp * bitweight ;
  74.    bitweight >>= 4 ;
  75.    return(temp) ;
  76. }
  77.  
  78. /* get a bit from the current input byte, or a new byte if no current byte */
  79. static boolean getbit()
  80. {
  81.    boolean temp ;
  82.    bitweight >>= 1 ;
  83.    if (bitweight == 0) {
  84.       inputbyte = pktopbm_pkbyte() ;
  85.       bitweight = 128 ;
  86.    }
  87.    temp = (inputbyte >= bitweight) ;
  88.    if (temp) inputbyte -= bitweight ;
  89.    return(temp) ;
  90. }
  91.  
  92. /* unpack a dynamically packed number. dynf is dynamic packing threshold  */
  93. static integer pkpackednum()
  94. {
  95.    integer i, j ;
  96.    i = getnyb() ;
  97.    if (i == 0) {            /* large run count, >= 3 nibbles */
  98.       do {
  99.      j = getnyb() ;            /* count extra nibbles */
  100.      i++ ;
  101.       } while (j == 0) ;
  102.       while (i > 0) {
  103.      j = (j<<4) + getnyb() ;    /* add extra nibbles */
  104.      i-- ;
  105.       }
  106.       return (j - 15 +((13 - dynf)<<4) + dynf) ;
  107.    } else if (i <= dynf) return (i) ;    /* number > 0 and <= dynf */
  108.    else if (i < 14) return (((i - dynf - 1)<<4) + getnyb() + dynf + 1) ;
  109.    else {
  110.       if (i == 14) repeatcount = pkpackednum() ;    /* get repeat count */
  111.       else repeatcount = 1 ;        /* value 15 indicates repeat count 1 */
  112.       return(pkpackednum()) ;
  113.    }
  114. }
  115.  
  116. /* skip specials in PK files, inserted by Metafont or some other program */
  117. static void
  118. skipspecials()
  119. {
  120.    integer i, j;
  121.    do {
  122.       flagbyte = pktopbm_pkbyte() ;
  123.       if (flagbyte >= 240)
  124.      switch(flagbyte) {
  125.      case 240:            /* specials of size 1-4 bytes */
  126.      case 241:
  127.      case 242:
  128.      case 243:
  129.         i = 0 ;
  130.         for (j = 240 ; j <= flagbyte ; j ++) i = (i<<8) + pktopbm_pkbyte() ;
  131.         for (j = 1 ; j <= i ; j ++) pktopbm_pkbyte() ;    /* ignore special */
  132.         break ;
  133.      case 244:            /* no-op, parameters to specials */
  134.         get32() ;
  135.      case 245:            /* start of postamble */
  136.      case 246:            /* no-op */
  137.         break ;
  138.      case 247:            /* pre-amble in wrong place */
  139.      case 248:
  140.      case 249:
  141.      case 250:
  142.      case 251:
  143.      case 252:
  144.      case 253:
  145.      case 254:
  146.      case 255:
  147.         pm_error("unexpected flag byte %d", flagbyte) ;
  148.      }
  149.    } while (!(flagbyte < 240 || flagbyte == 245)) ;
  150. }
  151.  
  152. /* ignore character packet */
  153. static void
  154. ignorechar(car, endofpacket)
  155.      integer car, endofpacket;
  156. {
  157.    while (pktopbm_pkloc != endofpacket) pktopbm_pkbyte() ;
  158.    if (car < 0 || car >= MAXPKCHAR)
  159.       pm_message("Character %d out of range", car) ;
  160.    skipspecials() ;
  161. }
  162.  
  163. int
  164. main(argc, argv)
  165.      int argc ;
  166.      char *argv[] ;
  167. {
  168.    integer endofpacket ;
  169.    boolean turnon ;
  170.    integer i, j;
  171.    integer car ;
  172.    bit row[MAXROWWIDTH+1] ;
  173.    char *usage = "pkfile[.pk] [[-c num] pbmfile]...";
  174.    
  175.    pbm_init(&argc, argv);
  176.    for (i = 0 ; i < MAXPKCHAR ; i ++) filename[i] = NULL ;
  177.  
  178.    pm_message("This is PKtoPBM, version 2.4") ;
  179.  
  180.    if (--argc < 1) pm_usage(usage) ;
  181.  
  182.    strcpy(pkname, *++argv) ;
  183.    pktopbm_add_suffix(pkname, ".pk") ;
  184.  
  185.    car = 0 ;
  186.    while (++argv, --argc) {
  187.       if (argv[0][0] == '-' && argv[0][1])
  188.      switch (argv[0][1]) {
  189.      case 'C':
  190.      case 'c':
  191.         if (argv[0][2]) car = atoi(*argv+2) ;
  192.         else if (++argv, --argc) car = atoi(*argv) ;
  193.         else pm_usage(usage) ;
  194.         break ;
  195.      default:
  196.         pm_usage(usage) ;
  197.      } else if (car < 0 || car >= MAXPKCHAR) {
  198.         pm_error("character must be in range 0 to %d (-c)", MAXPKCHAR-1) ;
  199.      } else filename[car++] = *argv ;
  200.    }
  201.  
  202.    pkfile = pm_openr(pkname);
  203.    if (pktopbm_pkbyte() != 247)
  204.       pm_error("bad PK file (pre command missing)") ;
  205.    if (pktopbm_pkbyte() != 89)
  206.       pm_error("wrong version of packed file") ;
  207.    j = pktopbm_pkbyte() ;                /* get header comment size */
  208.    for (i = 1 ; i <= j ; i ++) pktopbm_pkbyte() ;    /* ignore header comment */
  209.    get32() ;                    /* ignore designsize */
  210.    get32() ;                    /* ignore checksum */
  211.    if (get32() != get32())            /* h & v pixels per point */
  212.       pm_message("Warning: aspect ratio not 1:1") ;
  213.    skipspecials() ;
  214.    while (flagbyte != 245) {            /* not at postamble */
  215.       integer cheight, cwidth ;
  216.       FILE *ofp;
  217.  
  218.       dynf = (flagbyte>>4) ;            /* get dynamic packing value */
  219.       flagbyte &= 15 ;
  220.       turnon = (flagbyte >= 8) ;        /* black or white initially? */
  221.       if (turnon) flagbyte &= 7 ;        /* long or short form */
  222.       if (flagbyte == 7) {            /* long form preamble */
  223.      integer packetlength = get32() ;    /* character packet length */
  224.      car = get32() ;            /* character number */
  225.      endofpacket = packetlength + pktopbm_pkloc ;    /* calculate end of packet */
  226.      if (car >= MAXPKCHAR || car < 0) {
  227.         ignorechar(car, endofpacket);
  228.         continue;
  229.      }
  230.      get32() ;                 /* ignore tfmwidth */
  231.      get32() ;                /* ignore horiz escapement */
  232.      get32() ;                /* ignore vert escapement */
  233.      cwidth = get32() ;            /* bounding box width */
  234.      cheight = get32() ;            /* bounding box height */
  235.      if (cwidth < 0 || cheight < 0 || cwidth > 65535 || cheight > 65535) {
  236.         ignorechar(car, endofpacket);
  237.         continue;
  238.      }
  239.      get32() ;                /* ignore horiz offset */
  240.      get32() ;                /* ignore vert offset */
  241.       } else if (flagbyte > 3) {        /* extended short form */
  242.      integer packetlength = ((flagbyte - 4)<<16) + get16() ;
  243.                         /* packet length */
  244.      car = pktopbm_pkbyte() ;            /* char number */
  245.      endofpacket = packetlength + pktopbm_pkloc ;    /* calculate end of packet */
  246.      if (car >= MAXPKCHAR) {
  247.         ignorechar(car, endofpacket);
  248.         continue;
  249.      }
  250.      pktopbm_pkbyte() ;                 /* ignore tfmwidth (3 bytes) */
  251.      get16() ;                /* ignore tfmwidth (3 bytes) */
  252.      get16() ;                /* ignore horiz escapement */
  253.      cwidth = get16() ;            /* bounding box width */
  254.      cheight = get16() ;            /* bounding box height */
  255.      get16() ;                /* ignore horiz offset */
  256.      get16() ;                /* ignore vert offset */
  257.       } else {                    /* short form preamble */
  258.      integer packetlength = (flagbyte<<8) + pktopbm_pkbyte() ;
  259.                         /* packet length */
  260.      car = pktopbm_pkbyte() ;            /* char number */
  261.      endofpacket = packetlength + pktopbm_pkloc ;    /* calculate end of packet */
  262.      if (car >= MAXPKCHAR) {
  263.         ignorechar(car, endofpacket);
  264.         continue;
  265.      }
  266.      pktopbm_pkbyte() ;                 /* ignore tfmwidth (3 bytes) */
  267.      get16() ;                 /* ignore tfmwidth (3 bytes) */
  268.      pktopbm_pkbyte() ;                /* ignore horiz escapement */
  269.      cwidth = pktopbm_pkbyte() ;            /* bounding box width */
  270.      cheight = pktopbm_pkbyte() ;            /* bounding box height */
  271.      pktopbm_pkbyte() ;                /* ignore horiz offset */
  272.      pktopbm_pkbyte() ;                /* ignore vert offset */
  273.       }
  274.       if (filename[car]) {
  275.      bitmap = pbm_allocarray(cwidth, cheight) ;
  276.      if (bitmap == NULL)
  277.         pm_error("out of memory allocating bitmap") ;
  278.       } else {
  279.      ignorechar(car, endofpacket);
  280.      continue;
  281.       }
  282.       bitweight = 0 ;
  283.       if (dynf == 14) {                /* bitmapped character */
  284.      for (i = 0 ; i < cheight ; i ++)
  285.         for (j = 0 ; j < cwidth ; j ++) {
  286.            if (getbit())
  287.           bitmap[i][j] = PBM_BLACK ;
  288.            else
  289.           bitmap[i][j] = PBM_WHITE ;
  290.         }
  291.       } else {                    /* dynamically packed char */
  292.      integer rowsleft = cheight ;
  293.      integer hbit = cwidth ;
  294.      integer rp = 0;
  295.      repeatcount = 0 ;
  296.      while (rowsleft > 0) {
  297.         integer count = pkpackednum() ;    /* get current colour count */
  298.         while (count > 0) {
  299.            if (count < hbit) {        /* doesn't extend past row */
  300.           hbit -= count ;
  301.           while (count--)
  302.              row[rp++] = turnon ? PBM_BLACK : PBM_WHITE;
  303.            } else {                /* reaches end of row */
  304.           count -= hbit ;
  305.           while (hbit--)
  306.              row[rp++] = turnon ? PBM_BLACK : PBM_WHITE;
  307.           for (i = 0; i <= repeatcount; i++)    /* fill row */
  308.              for (j = 0; j < cwidth; j++)
  309.             bitmap[i + cheight-rowsleft][j] = row[j] ;
  310.           rowsleft -= repeatcount + 1;
  311.           repeatcount = rp = 0 ;
  312.           hbit = cwidth ;
  313.            }
  314.         }
  315.         turnon = !turnon ;
  316.      }
  317.      if (rowsleft != 0 || hbit != cwidth)
  318.         pm_error("bad pk file (more bits than required)") ;
  319.       }
  320.       if (endofpacket != pktopbm_pkloc)
  321.      pm_error("bad pk file (bad packet length)") ;
  322.  
  323.       ofp = pm_openw(filename[car]);
  324.       filename[car] = NULL;
  325.       pbm_writepbm(ofp, bitmap, cwidth, cheight, 0) ;
  326.       pbm_freearray(bitmap, cheight) ;
  327.       pm_close(ofp) ;
  328.       skipspecials() ;
  329.    }
  330.    while (! feof(pkfile)) pktopbm_pkbyte() ;        /* skip trailing junk */
  331.    pm_close(pkfile);
  332.    for (car = 0; car < MAXPKCHAR; car++)
  333.       if (filename[car])
  334.      pm_message("Warning: No character in position %d (file %s).",
  335.             car, filename[car]) ;
  336.    pm_message("%d bytes read from packed file.", pktopbm_pkloc-1) ;
  337.    exit(0);
  338. }
  339.